#include "gui/Slider.h"

#include "utilities/Rectangle.h"

namespace gui
{
	Slider::Slider() : scaleImage( NULL ), sliderImage( NULL )
	{
	}

	Slider::Slider( const gdn::Vector2f& thePos, float theWidth,
			        int theScaleMin, int theScaleMax, int theScaleDefault,
			        gdn::Image& theScaleImage, gdn::Image& theSliderImage,
			        const gdn::Rectanglei& theScaleLeft, const gdn::Rectanglei& theScaleMiddle, const gdn::Rectanglei& theScaleRight,
			        const gdn::Rectanglei& theSliderIdle, const gdn::Rectanglei& theSliderHover, const gdn::Rectanglei& theSliderPress )
	   : pos( thePos ), width( theWidth ),
	     scaleMin( theScaleMin ), scaleMax( theScaleMax ), scaleDefault( theScaleDefault ), currentScale( scaleDefault ),
	     scaleImage( &theScaleImage ), sliderImage( &theSliderImage ),
	     scaleLeft( theScaleLeft ), scaleMiddle( theScaleMiddle ), scaleRight( theScaleRight ),
	     sliderIdle( theSliderIdle ), sliderHover( theSliderHover ), sliderPress( theSliderPress ),
	     hold( false ), mousePos( 0, 0 )
	{
		slider.SetPosition( ( int )( pos.x + ( ( ( float )( scaleDefault ) / scaleMax ) * width ) - ( ( sliderIdle.width ) / 2 ) ), pos.y );
		slider.SetImage( *sliderImage );
		slider.SetSubRectangle( sliderIdle );
	}

	int Slider::Process( const gdn::Event& event )
	{
		if ( event.type == gdn::Event::MouseButtonPressed and event.mouseButton == gdn::Mouse::Left )
		{
			if ( util::RectangleContainsPoint< float >( gdn::Rectanglef( pos.x, pos.y, width, sliderIdle.height ), mousePos ) )
			{
				hold = true;

				ProcessSliderHighlight();
				MoveSlider();
			}
		}
		else if ( event.type == gdn::Event::MouseButtonReleased and event.mouseButton == gdn::Mouse::Left )
		{
			hold = false;

			ProcessSliderHighlight();
		}
		else if ( event.type == gdn::Event::MouseMoved )
		{
			mousePos.x = event.x;
			mousePos.y = event.y;

			ProcessSliderHighlight();
			MoveSlider();
		}

		return currentScale;
	}

	void Slider::Draw( gdn::Window& window )
	{
		DrawScale( window );
		window.Draw( slider );
	}

	void Slider::Draw( gdn::RenderImage& renderImage )
	{
		DrawScale( renderImage );
		renderImage.Draw( slider );
	}

	int Slider::GetCurrentScale() const
	{
		return currentScale;
	}

	void Slider::DrawScale( gdn::Window& window )
	{
		scale.SetPosition( pos.x, pos.y );
		scale.SetImage( *scaleImage );

		scale.SetSubRectangle( scaleLeft );
		window.Draw( scale );

		scale.SetSubRectangle( scaleRight );
		scale.SetPosition( pos.x + ( width - scaleRight.width ), pos.y );
		window.Draw( scale );

		scale.SetSubRectangle( scaleMiddle );
		for ( unsigned int i = ( pos.x + scaleLeft.width ); i < pos.x + ( width - scaleRight.width ); i += scaleMiddle.width )
		{
			scale.SetPosition( i, pos.y );
			window.Draw( scale );
		}
	}

	void Slider::DrawScale( gdn::RenderImage& renderImage )
	{
		scale.SetPosition( pos.x, pos.y );
		scale.SetImage( *scaleImage );

		scale.SetSubRectangle( scaleLeft );
		renderImage.Draw( scale );

		scale.SetSubRectangle( scaleRight );
		scale.SetPosition( pos.x + ( width - scaleRight.width ), pos.y );
		renderImage.Draw( scale );

		scale.SetSubRectangle( scaleMiddle );
		for ( unsigned int i = ( pos.x + scaleLeft.width ); i < pos.x + ( width - scaleRight.width ); i += scaleMiddle.width )
		{
			scale.SetPosition( i, pos.y );
			renderImage.Draw( scale );
		}
	}

	void Slider::ProcessSliderHighlight()
	{
		if ( hold and util::RectangleContainsPoint< float >( gdn::Rectanglef( slider.GetPosition().x, slider.GetPosition().y, sliderIdle.width, sliderIdle.height ), mousePos ) )
		{
			slider.SetSubRectangle( sliderPress );
		}
		else if ( !hold and util::RectangleContainsPoint< float >( gdn::Rectanglef( slider.GetPosition().x, slider.GetPosition().y, sliderIdle.width, sliderIdle.height ), mousePos ) )
		{
			slider.SetSubRectangle( sliderHover );
		}
		else
		{
			slider.SetSubRectangle( sliderIdle );
		}
	}

	void Slider::MoveSlider()
	{
		if ( hold == true )
		{
			gdn::Vector2f sliderPos( mousePos.x, pos.y );

			if ( mousePos.x < pos.x )
			{
				sliderPos.x = pos.x;
			}
			else if ( mousePos.x > ( pos.x + ( width - scaleRight.width ) ) )
			{
				sliderPos.x = ( pos.x + width );
			}

			sliderPos.x -= ( ( sliderIdle.width ) / 2 );

			slider.SetPosition( sliderPos );
			slider.SetSubRectangle( sliderPress );

			sliderPos.x += ( ( sliderIdle.width ) / 2 );

			float percentage = ( sliderPos.x - pos.x ) / width;
			currentScale = ( ( scaleMax - scaleMin ) * percentage ) + scaleMin;
		}
	}
}
